<template>
  <div class="security-view">
    <div class="header">
      <div class="header-top">
        <button @click="goBack" class="back-btn">
          <i class="icon">←</i>
          返回
        </button>
      </div>
      <h1>安全管理</h1>
      <p class="subtitle">管理IP黑名单和登录失败记录</p>
    </div>

    <!-- 导航标签 -->
    <div class="tabs">
      <button 
        :class="['tab-button', { active: activeTab === 'blacklist' }]"
        @click="activeTab = 'blacklist'"
      >
        IP黑名单 ({{ blacklistData.length }})
      </button>
      <button 
        :class="['tab-button', { active: activeTab === 'failures' }]"
        @click="activeTab = 'failures'"
      >
        登录失败记录 ({{ failuresData.length }})
      </button>
    </div>

    <!-- IP黑名单页面 -->
    <div v-if="activeTab === 'blacklist'" class="tab-content">
      <div class="actions">
        <button @click="loadBlockedIPs" class="refresh-btn">
          <i class="icon">🔄</i>
          刷新
        </button>
      </div>

      <div v-if="blacklistLoading" class="loading">
        加载中...
      </div>

      <div v-else-if="blacklistData.length === 0" class="empty-state">
        <div class="empty-icon">🛡️</div>
        <h3>暂无被封禁的IP</h3>
        <p>系统将自动封禁多次登录失败的IP地址</p>
      </div>

      <div v-else class="table-container">
        <table class="data-table">
          <thead>
            <tr>
              <th>IP地址</th>
              <th>封禁时间</th>
              <th>解封时间</th>
              <th>失败次数</th>
              <th>封禁原因</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="item in blacklistData" :key="item.id">
              <td class="ip-cell">{{ item.ip }}</td>
              <td>{{ formatTime(item.blocked_at) }}</td>
              <td>
                <span v-if="item.unblocked_at" :class="getStatusClass(item.unblocked_at)">
                  {{ formatTime(item.unblocked_at) }}
                </span>
                <span v-else class="permanent">永久封禁</span>
              </td>
              <td class="count-cell">{{ item.failure_count }}</td>
              <td class="reason-cell">{{ item.reason }}</td>
              <td class="actions-cell">
                <button 
                  @click="unblockIP(item.ip)"
                  :disabled="isUnblocking"
                  class="unblock-btn"
                  :title="'解封 ' + item.ip"
                >
                  <i class="icon">🔓</i>
                  解封
                </button>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>

    <!-- 登录失败记录页面 -->
    <div v-if="activeTab === 'failures'" class="tab-content">
      <div class="actions">
        <button @click="loadLoginFailures" class="refresh-btn">
          <i class="icon">🔄</i>
          刷新
        </button>
        <button @click="clearLoginFailures" class="clear-btn" :disabled="isClearing">
          <i class="icon">🗑️</i>
          清理记录
        </button>
      </div>

      <div v-if="failuresLoading" class="loading">
        加载中...
      </div>

      <div v-else-if="failuresData.length === 0" class="empty-state">
        <div class="empty-icon">📝</div>
        <h3>暂无登录失败记录</h3>
        <p>系统会记录所有登录失败的尝试</p>
      </div>

      <div v-else class="table-container">
        <table class="data-table">
          <thead>
            <tr>
              <th>IP地址</th>
              <th>用户名</th>
              <th>失败时间</th>
              <th>用户代理</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="item in failuresData" :key="item.id">
              <td class="ip-cell">{{ item.ip }}</td>
              <td class="username-cell">{{ item.username }}</td>
              <td>{{ formatTime(item.timestamp) }}</td>
              <td class="user-agent-cell" :title="item.user_agent">
                {{ formatUserAgent(item.user_agent) }}
              </td>
            </tr>
          </tbody>
        </table>

        <!-- 分页 -->
        <div v-if="pagination.total > pagination.page_size" class="pagination">
          <button 
            @click="previousPage"
            :disabled="pagination.page <= 1"
            class="page-btn"
          >
            上一页
          </button>
          <span class="page-info">
            第 {{ pagination.page }} 页，共 {{ Math.ceil(pagination.total / pagination.page_size) }} 页
          </span>
          <button 
            @click="nextPage"
            :disabled="pagination.page >= Math.ceil(pagination.total / pagination.page_size)"
            class="page-btn"
          >
            下一页
          </button>
        </div>
      </div>
    </div>

    <!-- 消息提示 -->
    <div v-if="message.text" :class="['message', message.type]">
      {{ message.text }}
    </div>
  </div>
</template>

<script>
import { API_BASE_URL, API_ENDPOINTS } from '@/config/api'
import { authService } from '@/services/authService'

export default {
  name: 'SecurityView',
  data() {
    return {
      activeTab: 'blacklist',
      blacklistData: [],
      failuresData: [],
      blacklistLoading: false,
      failuresLoading: false,
      isUnblocking: false,
      isClearing: false,
      message: {
        text: '',
        type: 'info'
      },
      pagination: {
        page: 1,
        page_size: 20,
        total: 0
      }
    }
  },
  mounted() {
    this.loadBlockedIPs()
    this.loadLoginFailures()
  },
  methods: {
    async loadBlockedIPs() {
      this.blacklistLoading = true
      try {
        const token = authService.getToken()
        const response = await fetch(`${API_BASE_URL}/security/blocked-ips`, {
          headers: {
            'Authorization': `Bearer ${token}`
          }
        })

        if (response.ok) {
          const data = await response.json()
          this.blacklistData = data.data || []
        } else {
          throw new Error('获取IP黑名单失败')
        }
      } catch (error) {
        console.error('加载IP黑名单失败:', error)
        this.showMessage('加载IP黑名单失败', 'error')
      } finally {
        this.blacklistLoading = false
      }
    },

    async loadLoginFailures() {
      this.failuresLoading = true
      try {
        const token = authService.getToken()
        const response = await fetch(
          `${API_BASE_URL}/security/login-failures?page=${this.pagination.page}&page_size=${this.pagination.page_size}`,
          {
            headers: {
              'Authorization': `Bearer ${token}`
            }
          }
        )

        if (response.ok) {
          const data = await response.json()
          this.failuresData = data.data || []
          this.pagination.total = data.total || 0
        } else {
          throw new Error('获取登录失败记录失败')
        }
      } catch (error) {
        console.error('加载登录失败记录失败:', error)
        this.showMessage('加载登录失败记录失败', 'error')
      } finally {
        this.failuresLoading = false
      }
    },

    async unblockIP(ip) {
      if (!confirm(`确定要解封IP地址 ${ip} 吗？`)) {
        return
      }

      this.isUnblocking = true
      try {
        const token = authService.getToken()
        const response = await fetch(`${API_BASE_URL}/security/blocked-ips/${encodeURIComponent(ip)}`, {
          method: 'DELETE',
          headers: {
            'Authorization': `Bearer ${token}`
          }
        })

        if (response.ok) {
          this.showMessage(`IP ${ip} 解封成功`, 'success')
          this.loadBlockedIPs() // 重新加载列表
        } else {
          const error = await response.json()
          throw new Error(error.error || '解封失败')
        }
      } catch (error) {
        console.error('解封IP失败:', error)
        this.showMessage(`解封IP失败: ${error.message}`, 'error')
      } finally {
        this.isUnblocking = false
      }
    },

    async clearLoginFailures() {
      if (!confirm('确定要清理所有登录失败记录吗？此操作不可恢复。')) {
        return
      }

      this.isClearing = true
      try {
        const token = authService.getToken()
        const response = await fetch(`${API_BASE_URL}/security/login-failures`, {
          method: 'DELETE',
          headers: {
            'Authorization': `Bearer ${token}`
          }
        })

        if (response.ok) {
          const data = await response.json()
          this.showMessage(`成功清理 ${data.deleted_count} 条记录`, 'success')
          this.loadLoginFailures() // 重新加载列表
        } else {
          const error = await response.json()
          throw new Error(error.error || '清理失败')
        }
      } catch (error) {
        console.error('清理登录失败记录失败:', error)
        this.showMessage(`清理失败: ${error.message}`, 'error')
      } finally {
        this.isClearing = false
      }
    },

    previousPage() {
      if (this.pagination.page > 1) {
        this.pagination.page--
        this.loadLoginFailures()
      }
    },

    nextPage() {
      const maxPages = Math.ceil(this.pagination.total / this.pagination.page_size)
      if (this.pagination.page < maxPages) {
        this.pagination.page++
        this.loadLoginFailures()
      }
    },

    formatTime(timeString) {
      if (!timeString) return ''
      const date = new Date(timeString)
      return date.toLocaleString('zh-CN', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit'
      })
    },

    formatUserAgent(userAgent) {
      if (!userAgent) return ''
      if (userAgent.length > 50) {
        return userAgent.substring(0, 50) + '...'
      }
      return userAgent
    },

    getStatusClass(unblockTime) {
      if (!unblockTime) return ''
      const now = new Date()
      const unblock = new Date(unblockTime)
      return unblock > now ? 'future' : 'past'
    },

    showMessage(text, type = 'info') {
      this.message = { text, type }
      setTimeout(() => {
        this.message.text = ''
      }, 5000)
    },

    goBack() {
      // 导航回主页
      this.$router.push('/')
    }
  }
}
</script>

<style scoped>
.security-view {
  padding: 24px;
  max-width: 1200px;
  margin: 0 auto;
  min-height: 100vh;
  box-sizing: border-box;
}

.header {
  margin-bottom: 32px;
}

.header h1 {
  font-size: 28px;
  font-weight: 600;
  color: #1f2937;
  margin: 0 0 8px 0;
}

.subtitle {
  color: #6b7280;
  font-size: 16px;
  margin: 0;
}

.tabs {
  display: flex;
  border-bottom: 2px solid #e5e7eb;
  margin-bottom: 24px;
}

.tab-button {
  padding: 12px 24px;
  background: none;
  border: none;
  font-size: 16px;
  font-weight: 500;
  color: #6b7280;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all 0.2s;
}

.tab-button:hover {
  color: #374151;
}

.tab-button.active {
  color: #3b82f6;
  border-bottom-color: #3b82f6;
}

.tab-content {
  min-height: 600px;
  display: flex;
  flex-direction: column;
  animation: fadeIn 0.3s ease-in-out;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.actions {
  display: flex;
  gap: 12px;
  margin-bottom: 24px;
  flex-shrink: 0;
}

.refresh-btn, .clear-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  background: white;
  color: #374151;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.2s;
}

.refresh-btn:hover {
  background: #f9fafb;
  border-color: #9ca3af;
}

.clear-btn {
  border-color: #ef4444;
  color: #ef4444;
}

.clear-btn:hover {
  background: #fef2f2;
}

.loading {
  text-align: center;
  padding: 48px;
  color: #6b7280;
  font-size: 16px;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.empty-state {
  text-align: center;
  padding: 48px;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.empty-icon {
  font-size: 48px;
  margin-bottom: 16px;
}

.empty-state h3 {
  color: #374151;
  margin: 0 0 8px 0;
  font-size: 18px;
}

.empty-state p {
  color: #6b7280;
  margin: 0;
}

.table-container {
  background: white;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  flex: 1;
  min-height: 400px;
  display: flex;
  flex-direction: column;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  flex: 1;
}

.data-table th {
  background: #f9fafb;
  padding: 12px 16px;
  text-align: left;
  font-weight: 600;
  color: #374151;
  border-bottom: 1px solid #e5e7eb;
}

.data-table td {
  padding: 12px 16px;
  border-bottom: 1px solid #f3f4f6;
  vertical-align: top;
}

.data-table tr:hover {
  background: #f9fafb;
}

.ip-cell {
  font-family: monospace;
  font-weight: 500;
  color: #1f2937;
}

.count-cell {
  text-align: center;
  font-weight: 600;
  color: #ef4444;
}

.reason-cell {
  max-width: 200px;
  color: #6b7280;
}

.username-cell {
  font-weight: 500;
  color: #374151;
}

.user-agent-cell {
  max-width: 300px;
  color: #6b7280;
  font-size: 14px;
}

.permanent {
  color: #ef4444;
  font-weight: 500;
}

.future {
  color: #f59e0b;
}

.past {
  color: #10b981;
}

.actions-cell {
  text-align: center;
}

.unblock-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 12px;
  background: #10b981;
  color: white;
  border: none;
  border-radius: 4px;
  font-size: 12px;
  cursor: pointer;
  transition: background 0.2s;
}

.unblock-btn:hover:not(:disabled) {
  background: #059669;
}

.unblock-btn:disabled {
  background: #d1d5db;
  cursor: not-allowed;
}

.pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 16px;
  padding: 16px;
  border-top: 1px solid #e5e7eb;
  flex-shrink: 0;
  margin-top: auto;
}

.page-btn {
  padding: 8px 16px;
  border: 1px solid #d1d5db;
  border-radius: 4px;
  background: white;
  color: #374151;
  cursor: pointer;
  transition: all 0.2s;
}

.page-btn:hover:not(:disabled) {
  background: #f9fafb;
  border-color: #9ca3af;
}

.page-btn:disabled {
  background: #f9fafb;
  color: #9ca3af;
  cursor: not-allowed;
}

.page-info {
  color: #6b7280;
  font-size: 14px;
}

.message {
  position: fixed;
  top: 20px;
  right: 20px;
  padding: 12px 20px;
  border-radius: 6px;
  color: white;
  font-weight: 500;
  z-index: 1000;
  animation: slideIn 0.3s ease;
}

.message.success {
  background: #10b981;
}

.message.error {
  background: #ef4444;
}

.message.info {
  background: #3b82f6;
}

@keyframes slideIn {
  from {
    transform: translateX(100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

.icon {
  font-style: normal;
}

.header-top {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 16px;
}

.back-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 16px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  background: white;
  color: #374151;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.2s;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}

.back-btn:hover {
  background: #f9fafb;
  border-color: #9ca3af;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.back-btn .icon {
  font-size: 16px;
  font-weight: bold;
}
</style> 